# -*- coding: utf-8 -*-
from copy import deepcopy

from decimal import Decimal

from datetime import datetime, date
from collections import Iterable

from typing import List, Dict


from settings import CLASSDATADICT, db_config, online_config
from util.DataQuery.DbTools import DbTools
from util.DataQuery.hzflowOperation import hzflowOperation
from util.g import g

if g.db_con == 'localhost':
    db_config = db_config
if g.db_con == 'online':
    db_config = online_config



class FormDataQuery():

    func_param_list = None
    dict_cursor = g.dict_cursor

    # 用来接收查询数据的 sql
    sql = None

    def __init__(self, class_name=""):
        db_info = CLASSDATADICT.get(class_name)
        self.class_name = class_name
        self.db_info = db_info
        if not db_info:
            raise NameError(
                f'in {self.__class__.__name__} ------------ Class name passed in error.'
                f'This class {class_name} is not in CLASSDATADICT. --custom--')
        database = db_info.get('database')
        self.fields = db_info.get('fields')
        self.dict_value = db_info.get('dict_value')
        self.database = database

    # def __del__(self): # 查询结束后关闭数据库连接。
    #     self.client_obj.close()
    #     self.cursor.close()

    def get_client_obj(self, database):
        # return pymysql.Connection(host=db_config.get('host'), user=db_config.get('user'), password=db_config.get('password'),
        #                           database=database, port=db_config.get('port'), charset=db_config.get('charset'))
        if database == "hitech":
            return g.hitech_pool.connection()

    def get_sql_str(self):
        # sql = 'select {} from {}'.format(",".join(self.check_fields), self.db_info.get('table'))
        sql = 'select * from {}'.format(self.db_info.get('table'))
        where_list = self.db_info.get('condition').get('where')
        if where_list:
            sql += ' where {}'.format(' '.join(where_list))

        co_id = deepcopy(g.co_id)
        year = deepcopy(g.year)
        if 'g.co_id' in sql: sql = sql.replace('g.co_id', str(co_id))
        if 'g.year' in sql: sql = sql.replace('g.year', str(year))
        return sql

    def get_datas(self, sql=None):
        client_obj = self.get_client_obj(database=self.database)
        cursor = client_obj.cursor(cursor=self.dict_cursor)

        if sql is None:
            sql = self.get_sql_str()
        else:
            sql = sql
        self.sql = sql
        result = []
        try:
            cursor.execute(sql)
            result = cursor.fetchall()
        except Exception as err:
            g.logger.error("查询数据错误: err: {}".format(err))
        finally:
            cursor.close()
            client_obj.close()
        return list(result)
    # # TODO 将数据 按照 self.fields 中的顺序排列好， 然后将字典值转换为正确的值。
    # # TODO 转换字典值操作应该在 for 循环中使用， 先判断该字段是否在 dict_value 中，然后做出对应操作。
    # # FormDateDecorator 中需要调用 func_data 方法。
    def func_data(self):
        result = self.get_datas()

        # 当 class_name 是 WriteIPForm 时 读取 ent_res_ipn 数据并加入到 result 中
        if self.sql is not None and self.class_name == "WriteIPForm":
            ipn_data = self.get_datas(sql=self.sql.replace("ent_res_ipr", "ent_res_ipn"))
            for ipn in ipn_data:
                ipn["is_nip"] = True
            result.extend(ipn_data)

        # 使用列表推导式为 result 中的每一个 dict 调用 handle_data 方法
        total = [self.handle_data_rdict(dic=i) for i in result]
        return total

    def get_dict_label(self, value, typ):
        client_obj = self.get_client_obj(database='hitech')
        cursor = client_obj.cursor()
        # # # 将未上市的值排除
        if typ == 'HAN08' and (value == 0 or value=='0'):
            # print('直接返回')
            cursor.close()
            client_obj.close()
            return value

        elif "," in str(value):
            ret = list()
            for i in value.split(","):
                ret.append(self.select_dict_value(value=i, typ=typ, client_obj=None, cursor=cursor))
            # print(ret)
            if not all(ret):
                return ''
            else:
                return "#".join(ret)
                # return ''
        else:
            return self.select_dict_value(value=value, typ=typ, client_obj=client_obj, cursor=cursor)


    def select_dict_value(self, value, typ, client_obj=None, cursor=None):
        if type(value) == int:
            value = str(value)
        if value is None or not value:
            return ""
        elif typ == "trans_form":
            # TODO 这里需要处理 值为其他的情况
            sql = f'select label from sys_dict where id={value} and type="{typ}"'
            if value == "0":
                return "其他"
        else:
            sql = f'select label from sys_dict where value="{value}" and type="{typ}"'
        # print(f'{self.class_name} \n {sql} \n\n')
        # print(sql)
        try:
            count = cursor.execute(sql)
        except Exception as err:
            g.logger.error("查询错误 sql={} err={}".format(sql, err))
        # # # 这里的 count 为受影响的行数， 要取返回的值需要调用 cursor 的 fetch 方法获取。
        # print(count, 'in FormDataQuery.get_dictlabel', f'\tparams is value: {value} type: {typ}')
        # print(count, value, typ)
        if not count:
            raise Exception(f'value error. --custom-- in FormDataQuery().get_dict_label value={value} type={typ}, sql={sql}')
        label = cursor.fetchone()
        # print(label)
        if not client_obj:
            return label[0] if isinstance(label, Iterable) else label
        cursor.close()
        client_obj.close()
        return label[0] if isinstance(label, Iterable) else label

    @property
    def check_fields(self):
        if not self.func_param_list:
            return self.fields
        for i, ele in enumerate(self.func_param_list[:]):
            if ele not in self.fields:
                self.func_param_list.remove(ele)
        # 增加 is_nip这个 field
        if self.class_name == "WriteIPForm":
            self.func_param_list.append("is_nip")
        return self.func_param_list

    def sort_params(self, param_dict:Dict) -> List:
        result = list()
        for fi in self.check_fields:
            a = param_dict.get(fi)
            result.append(a)
        return result


    def handle_data_rdict(self, dic: dict) -> dict:
        result = dict()
        # 这里将 装饰器获取到的函数参数列表与 fields 对比， 如果参数列表中的字段不在装饰器中， 则将其删除。
        for fi in self.check_fields:  # SCALE
            # 这里还需要处理 datetime 类型的数据 其中 既有 datetime.date 类型的， 又有 datetime.datetime 类型的。
            # fi 为字段名 --- a 为字段值
            a = dic.get(fi)
            if a is None:
                continue
            if type(a) == Decimal:
                a = str(a)
            if type(a) == datetime or type(a) == date:
                a = a.strftime('%Y-%m-%d')
            # #  这里还需要判断该字段是否在字典值列表中，需要在 sys_dict 表中查找 得到 label 值
            # # 查询字典值表 时，需要传入的参数， value、 type , type 在 dict_value 中可以取到。
            # 这里 STOCKCAT 为 0 时表示 该公司为上市 所以不 在 sys_dict 中获取 其对应的值
            if fi in self.dict_value:
                a = self.get_dict_label(value=a, typ=self.dict_value.get(fi))
            result[fi] = a
        # print(f'{fields} ------- {result}, --------------- {dic}\n\n')
        up_id = dic.get('ID')
        low_id = dic.get('id')
        result['id'] = low_id if not up_id else up_id
        return result

    # 查看企业材料是否撤回过
    def check_revert(self):
        status = DbTools.get_entresstatus_by_co_id(co_id=g.co_id, year=g.year)
        # 当材料状态为撤回中 或 撤回被拒绝时停止上传
        if not status:
            return False
        if status.get("fb_status") in [1, 3]:
            return True
        if status.get("fb_status") in [0, 2]:
            flow_obj = hzflowOperation.get_log(co_id=g.co_id, year=g.year)
            if not flow_obj:
                return False
            if status.get("fb_time") != flow_obj.fb_time:
                return True
        return False

    def handle_data(self, dic:dict) -> List:

        result = list()
        # # # TODO 这里将 装饰器获取到的函数参数列表与 fields 对比， 如果参数列表中的字段不在装饰器中， 则将其删除。
        for fi in self.check_fields: # SCALE
            # TODO 这里还需要处理 datetime 类型的数据 其中 既有 datetime.date 类型的， 又有 datetime.datetime 类型的。
            # fi 为字段名 --- a 为字段值
            a = dic.get(fi)
            if type(a) == Decimal:
                a = str(a)
            if type(a) == datetime or type(a) == date:
                a = a.strftime('%Y-%m-%d')
            # # TODO 这里还需要判断该字段是否在字典值列表中，需要在 sys_dict 表中查找 得到 label 值。  ----------- completed
            # # 查询字典值表 时，需要传入的参数， value、 type , type 在 dict_value 中可以取到。
            # TODO 这里 STOCKCAT 为 0 时表示 该公司为上市 所以不 在 sys_dict 中获取 其对应的值
            if fi in self.dict_value:
                a = self.get_dict_label(value=a, typ=self.dict_value.get(fi))
            result.append(a)
        # print(f'{fields} ------- {result}, --------------- {dic}\n\n')
        return result






if __name__ == '__main__':
    class_list = ['WriteApplicationCover', 'WriteRegistrationForm', 'WriteCivilType', 'WriteLegalType', 'WriteVentureInvestment', 'WriteIPForm', 'WriteHRInfo',
                  'WriteHRSubinfo', 'WriteRDForm', 'WriteRdcostForm', 'WritePSForm', 'WriteMaincaseForm', 'WriteOptcond', 'WriteInnovationAbilityForm', 'IAStaDesc', 'WriteStandForm']
    # 全部数据测试
    # for i in class_list:
    #
    #     db_obj = FormDataQuery(i)
    #     fields = db_obj.fields
    #
    #     r = db_obj.get_datas()
    #     d = db_obj.func_data()
    #     print(db_obj.class_name)
    #     print(d)
    #     print('\n\n')
    # 单个模块数据测试

    # db_obj = FormDataQuery('WriteInnovationAbilityForm')
    # a = db_obj.func_data()
    # print(a)
    # print(len(a[0]))

    a = FormDataQuery('WriteRegistrationForm')
    a.get_dict_label(value=0, typ='ent_scale')

    dic = a.func_data()[0]

    print(dic)
    print(a.sort_params(param_dict=dic))






